package com.example.demo.service.impl;

import com.example.demo.entity.ChapterList;
import com.example.demo.entity.Novel;
import com.example.demo.exception.BaseException;
import com.example.demo.mapper.NovelMapper;
import com.example.demo.reptile.CrawlNovel;
import com.example.demo.service.NovelService;
import com.example.demo.util.SqlSessionFactoryUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * @author wan
 * @version 1.0.0
 * @Description 小说业务处理层
 * @createTime 2021年08月26日 11:56:16
 */
@Slf4j
@Service
public class NovelServiceImpl implements NovelService {
    static SqlSession sqlSession = SqlSessionFactoryUtil.getSqlSession();
    //动态代理
    static NovelMapper mapper = sqlSession.getMapper(NovelMapper.class);

    public static final String LOCAL = "local";

    public static final String NONE = "none";

    @Override
    public List<Novel> getNovels() {
        return mapper.getNovels();
    }

    @Override
    public List<String> getNovel(String name, int pageNum) {
        //获取小说路径
        String path = getLocalPath(name);
        //根据路径读取小说
        return getFile(path, pageNum);
    }

    @Override
    public List<String> getNovelFromInternet(String novelName, String novelPath, int pageNum, String url1) {
        Novel novel = Novel.builder().novelName(novelName).path(url1).build();
        insertNovel(novel);
        //先缓冲一章看着
        List<ChapterList> novelChapterList = CrawlNovel.getNovelChapterList(novelPath);
        if (CollectionUtils.isEmpty(novelChapterList)) {
            return null;
        }
        String chapterUrl = novelChapterList.get(0).getChapterUrl();
        //爬取一章
        List<String> firstNovelChapterListDetail = CrawlNovel.getNovelChapterListDetail(chapterUrl);
        //写入一章
        writeFile(firstNovelChapterListDetail, url1);
        novelChapterList.remove(0);
        //再缓冲后面的
        CompletableFuture.runAsync(() -> {
            for (ChapterList cl : novelChapterList
            ) {
                String url = cl.getChapterUrl();
                //爬取一章
                List<String> novelChapterListDetail = CrawlNovel.getNovelChapterListDetail(url);
                //写入一章
                writeFile(novelChapterListDetail, url1);
                ChapterList chapterList = novelChapterList.get(0);
                if (chapterList == cl) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        log.error(e.getMessage(), e);
                        throw new BaseException("文件写入异常：" + e.getMessage());
                    }
                }
            }
        });
        return getFile(url1, pageNum);
    }


    /**
     * 获取路径
     *
     * @param name
     * @return
     */
    public static String getLocalPath(String name) {
        return mapper.getPath(name);
    }

    /**
     * 功能描述：
     * -- 校验小说能不能被搜到
     *
     * @param novelName
     * @return none：不存在 local：本地存在 其他：本地不存在，网络存在
     * @author : wan
     * @since : 2022/8/18 下午2:52
     */
    @Override
    public String novelVerification(String novelName) {
        //本地是否存在该小说
        if (pathCheck(novelName)) {
//            sqlSession.commit();
            return LOCAL;
        }
        //网络是否存在该小说
        List<String> html = CrawlNovel.getNovelHtml(CrawlNovel.urlSplice(novelName));
        String novelPath = CrawlNovel.getNovelPath2Html(html, novelName);
        if (!StringUtils.isBlank(novelPath)){
            return novelPath;
        } else {
            return NONE;
        }
    }

    /**
     * 得到文件
     *
     * @param path
     * @return
     */
    private List<String> getFile(String path, int pageNum) {
        List<String> list = new ArrayList<>();
        try {
            File file = new File(path);
            FileInputStream fis = new FileInputStream(file);
            InputStreamReader isr = new InputStreamReader(fis);
            BufferedReader br = new BufferedReader(isr);
            String text = null;
            for (int i = 0; i < (pageNum - 1) * 30; i++) {
                br.readLine();
            }
            while ((text = br.readLine()) != null) {
                list.add(text);
                if (list.size() == 30) {
                    break;
                }
            }
        } catch (Exception e) {
            log.error("产生异常:{}", e.getMessage());
            log.error(e.getMessage(), e);
            throw new BaseException("本地文件读取异常");
        }
        return list;
    }

    /**
     * 向本地写文件
     *
     * @param list
     * @param url
     */
    public void writeFile(List<String> list, String url) {
        File file = new File(url);
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        }
        FileOutputStream fos = null;
        PrintWriter pw = null;
        try {
            fos = new FileOutputStream(file, true);
            pw = new PrintWriter(fos);
            for (String l : list
            ) {
                pw.write(l);
                pw.flush();
                pw.write("\r\n");
                pw.flush();
            }
            pw.close();
            fos.close();
        } catch (Exception e) {
            log.error("写出文件产生异常：" + e.getMessage());
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 新增小说
     *
     * @param novel
     */
    private void insertNovel(Novel novel) {
        int i = mapper.insertNovel(novel);
        if (i != 1) {
            throw new BaseException(404, "小说新增失败");
        }
        sqlSession.commit();
    }

    @Override
    public void loadNovel(String novelName) {

    }

    /**
     * 获取novelService对象
     * 多态
     *
     * @return
     */
    public static NovelService getObject() {
        final NovelService novelService = new NovelServiceImpl();
        return novelService;
    }

    /**
     * 校验本地是否存在该小说
     * 正确：true
     * 反之：false
     *
     * @param novelName
     * @return
     */
    public static boolean pathCheck(String novelName) {
        String localPath = getLocalPath(novelName);
        if (StringUtils.isBlank(localPath) || !new File(localPath).exists()) {
            mapper.deleteNovel(novelName);
            sqlSession.commit();
            return false;
        }
        return true;
    }

}
